/*
Copyright (C) 2006-2007 The OZI Project
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
are met:
1. Redistributions of source code must retain the above copyright
notice, this list of conditions, and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright
notice, this list of conditions, and the disclaimer that follows 
these conditions in the documentation and/or other materials 
provided with the distribution.
3. The name "OZI" must not be used to endorse or promote products
derived from this software without prior written permission.  For
written permission, please contact The OZI Project.
4. Products derived from this software may not be called "OZI", nor
may "OZI" appear in their name, without prior written permission
from The OZI Project.
In addition, we request (but do not require) that you include in the 
end-user documentation provided with the redistribution and/or in the 
software itself an acknowledgement equivalent to the following:
"This product includes software developed by The OZI Project."
THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED.  IN NO EVENT SHALL THE JDOM AUTHORS OR THE PROJECT
CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
SUCH DAMAGE.
This software consists of voluntary contributions made by many 
individuals on behalf of The OZI Project and was originally 
created by Matt Jezorek <mjezorek@bellsouth.net>.  
 */
package com.ozi.utils;

import java.net.URL;
import java.util.Properties;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.io.FileInputStream;

import org.apache.log4j.PropertyConfigurator;
import org.apache.log4j.Logger;

/**
 * Configuration class that handles the configuration of ozi-lib
 * This will attempt to load the default configuration from the jar
 * but can be overwritten with system properties
 * 
 * The class loads in the following order
 * 1. built in ozi.properties
 * 2. ozi-agent.config
 * @author <a href="http://oziproject.org">OZI Project Team</a>
 */
public class Configurator {

    private static boolean loaded = false;
    private static Properties properties = new Properties();
    private static Logger log = Logger.getLogger(Configurator.class);
    private static String UD_CONFIG_PROPERTY = "ozi-agent.config";
    private static Configurator instance = new Configurator();

    private Configurator() {

        synchronized (properties) {
            if (!loaded) {
                loadBaseProperties();

                if (System.getProperty(UD_CONFIG_PROPERTY) != null) {
                    log.debug("loading custom config file");
                    try {
                        load(new FileInputStream(System.getProperty(UD_CONFIG_PROPERTY)));
                    } catch (FileNotFoundException e) {
                        log.error(e);
                    } catch (IOException e) {
                        log.error(e);
                    }
                }
            }
        }
        banner();

    }

    public static Configurator createConfig() {
        return (instance);
    }

    private void loadBaseProperties() {
        URL config = this.getClass().getClassLoader().getResource(Constants.CONFIG_FILE);
        log.info("loading default properties from resource:" + config);
        try {
            properties.load(config.openStream());
            PropertyConfigurator.configure(config);
        } catch (Exception e) {
            System.out.println("Generic error loading configuration file: " + Constants.CONFIG_FILE);
            e.printStackTrace();
            System.exit(1);

        }
        loaded = true;
        log.warn("*********** OZI Configured ***********");
    }

    public static void load(InputStream ins) throws IOException {
        try {
            properties.load(ins);
        } catch (IOException e) {
            log.error("Error loading custom custom properties", e);
            throw (e);
        }

    }

    public static void banner() {

        System.out.println("====================================================");
        System.out.println("               " + get(Constants.BANNER));
        System.out.println("====================================================");
        System.out.println("Version: " + get(Constants.VERSION));
        System.out.println("Protocol support: " + get(Constants.PROTOCOL_VERSION));
        System.out.println("====================================================");


    }

    /**
     * Returns a config entry referenced by key
     *
     * @param key the config entry name
     * @return the value that matches that key
     *
     */
    public static String get(String key) {
        log.debug(String.format("request for key [%s]", key));
        String ret = System.getProperty(key);
        if (ret == null) {
            return (properties.getProperty(key));
        }
        return (ret);

    }

    /**
     * Sets a config entry referenced by key
     *
     * @param key the property name
     * @param value the value that the key will have
     *
     */
    public static void set(String key, String value) {
        properties.setProperty(key, value);
        return;
    }

    public static String getOrException(String key) throws Exception {
        String ret = get(key);
        if (ret == null) {
            throw new Exception(String.format("incorrect OR missing tag [%s] in your configuration file", key));
        }
        return (ret);
    }
}
